package com.lkl.hystrixdemo.order.zookeeper.zkDistributeLock;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 模板方法模式
 *
 * 抽取公共的方法 getLock 和 unLock
 *
 */
public abstract class AbstractZkDistributeLock implements ZkDisytibuteLock {

    private final String url = "127.0.0.1:2181";

    private final String path = "/zookeeper/lock";

    private ZkClient zkClient = new ZkClient(url);

    /**
     * 执行业务逻辑
     */
    public abstract void doAction();

    @Override
    public void getLock() {
        //如果获取锁成功，继续执行业务方法
        if (tryLock()) {
            System.out.println(Thread.currentThread().getName() + "，成功获取到锁");
            doAction();
            unLock();
            System.out.println(Thread.currentThread().getName() + "，释放锁");
        } else {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            IZkChildListener zkChildListener = new IZkChildListener() {
                @Override
                public void handleChildChange(String s, List<String> list) throws Exception {
                    System.out.println(Thread.currentThread().getName() + "，监听到节点的变化，当前线程继续争抢锁的资源");
                    countDownLatch.countDown();
                }
            };
            zkClient.subscribeChildChanges(path, zkChildListener);
            try {
                countDownLatch.await();
                zkClient.unsubscribeChildChanges(path, zkChildListener);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            getLock();
        }
    }

    /**
     * 尝试获取锁
     * @return
     */
    private boolean tryLock() {
        if (zkClient == null) {
            return false;
        }
        try {
            //如果成功创建， 表示获取到锁
            zkClient.create(path, path, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        }catch (Exception e) {
            System.out.println(Thread.currentThread().getName() + ",未获取到锁");
            //e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 释放锁
     */
    @Override
    public void unLock() {
        if (zkClient != null) {
            zkClient.close();
        }
    }
}
